#include "datacenter.h"
#include <QStandardPaths>
#include <QDir>
#include <QFile>
#include <QJsonObject>
#include <QJsonDocument>


namespace model
{
DataCenter* DataCenter::instance = nullptr;

DataCenter* DataCenter::getInstance()
{
    static DataCenter instance;
    return &instance;
}

DataCenter::~DataCenter()
{
    //直接delete指针是可以的，C++标准中是允许的
    delete myself;
    delete friendList;
    delete chatSessionList;
    delete memberList;
    delete applyList;
    delete recentMessages;
    delete unreadMessageCount;
    delete searchUserInfoResult;
    delete searchMessageResult;
}

DataCenter::DataCenter() : netClient(this)
{
    // 此处只是把这几个 hash 类型的属性 new 出实例. 其他的 QList 类型的属性, 都暂时不实例化.
    // 主要是为了使用 nullptr 表示 "非法状态"
    // 对于 hash 来说, 不关心整个 QHash 是否是 nullptr, 而是关心, 某个 key 对应的 value 是否存在~~
    // 通过 key 是否存在, 也能表示该值是否有效.
    recentMessages = new QHash<QString, QList<Message>>();
    memberList = new QHash<QString, QList<UserInfo>>();
    unreadMessageCount = new QHash<QString, int>();

    // 加载数据
    loadDataFile();
}

void DataCenter::initWebsocket()
{
    netClient.initWebsocket();
}

//初始化数据文件
void DataCenter::initDataFile()
{
    //构造出文件的路径
    QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
    QString filePath = basePath + "/ChatClient.json";
    LOG() << "filePath: " << filePath;

    //将文件夹创建出来
    QDir dir;
    if(!dir.exists(basePath)) {
        dir.mkpath(basePath);
    }

    //创建文件
    QFile file(filePath);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        LOG() << "打开文件失败!" << file.errorString();
        return;
    }

    //初始化文件
    QString data = "{\n\n}";
    file.write(data.toUtf8());
    file.close();
}

//持久化文件
void DataCenter::saveDataFile()
{
    QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/ChatClient.json";
    QFile file(filePath);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        LOG() << "文件打开失败!" << file.errorString();
        return;
    }

    QJsonObject jsonObj;
    jsonObj["loginSessionId"] = loginSessionId;
    QJsonObject jsonUnread;
    for(auto it = unreadMessageCount->begin(); it != unreadMessageCount->end(); ++it) {
        jsonUnread[it.key()] = it.value();
    }
    jsonObj["unread"] = jsonUnread;

    //将json写入到文件中
    QJsonDocument jsonDoc(jsonObj);
    //将json转换为QString
    QString s = jsonDoc.toJson();
    file.write(s.toUtf8());

    file.close();
}
//加载文件到内存中
void DataCenter::loadDataFile()
{
    QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/ChatClient.json";

    //判断文件是否存在，如果不存在，则初始化，并创建空白的json文件
    QFileInfo fileInfo(filePath);
    if(!fileInfo.exists()) {
        initDataFile();
    }

    //读方式打开文件
    QFile file(filePath);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        LOG() << "文件打开失败!" << file.errorString();
        return;
    }

    //读取文件内容，并解析为json格式
    QJsonDocument JsonDoc = QJsonDocument::fromJson(file.readAll());
    if(JsonDoc.isNull()) {
        LOG() << "解析 JSON 文件失败！ JSON文件格式有错误";
        return;
    }

    QJsonObject jsonObj = JsonDoc.object();
    this->loginSessionId = jsonObj["loginSessionId"].toString();
    LOG() << "logSessionId: " << this->loginSessionId;

    this->unreadMessageCount->clear();
    // 这里不是JsonDoc，而是对jsonObj中内容操作
    // QJsonObject jsonUnread = JsonDoc["unread"].toObject();
    QJsonObject jsonUnread = jsonObj["unread"].toObject();
    for(auto it = jsonUnread.begin(); it != jsonUnread.end(); ++it) {
        this->unreadMessageCount->insert(it.key(),it.value().toInt());
    }

    file.close();
}

void DataCenter::clearUnread(const QString &chatSessionId)
{
    (*unreadMessageCount)[chatSessionId] = 0;

    // 清空的时候，将结果保存到文件中
    saveDataFile();
}

void DataCenter::addUnread(const QString &chatSessionId)
{
    (*unreadMessageCount)[chatSessionId]++;
    saveDataFile();
    LOG() <<  (*unreadMessageCount)[chatSessionId];
}

int DataCenter::getUnread(const QString &chatSessionId)
{
    return (*unreadMessageCount)[chatSessionId];
}

void DataCenter::getMyselfAsync()
{
    // DataCenter只负责处理数据， 网络通信还是NetClient
    netClient.getMyself(loginSessionId);
}

UserInfo *DataCenter::getMyself()
{
    return myself;
}

void DataCenter::resetMyself(std::shared_ptr<lch_im::GetUserInfoRsp> resp)
{
    if(myself == nullptr) {
        myself = new UserInfo();
    }

    const lch_im::UserInfo& userInfo = resp->userInfo();
    myself->load(userInfo);
}

void DataCenter::getFriendListAsync()
{
    netClient.getFriendList(loginSessionId);
}

QList<UserInfo>* DataCenter::getFriendList()
{
    return friendList;
}

void DataCenter::resetFriendList(std::shared_ptr<lch_im::GetFriendListRsp> resp)
{
    if(friendList == nullptr) {
        friendList = new QList<UserInfo>();
    }

    // 先清空好友列表
    friendList->clear();

    QList<lch_im::UserInfo>& friendListPB = resp->friendList();
    for(auto& f : friendListPB) {
        UserInfo userInfo;
        userInfo.load(f);
        friendList->push_back(userInfo);
    }
}

void DataCenter::getChatSessionListAsync()
{
    netClient.getChatSessionList(loginSessionId);
}

QList<ChatSessionInfo> *DataCenter::getChatSessionList()
{
    return chatSessionList;
}

void DataCenter::resetChatSessionList(std::shared_ptr<lch_im::GetChatSessionListRsp> resp)
{
    if(chatSessionList == nullptr) {
        chatSessionList = new QList<ChatSessionInfo>();
    }

    // 先清空好友列表
    chatSessionList->clear();

    QList<lch_im::ChatSessionInfo>& chatSessionListPB = resp->chatSessionInfoList();
    for(auto& f : chatSessionListPB) {
        ChatSessionInfo  chatSessionInfo;
        chatSessionInfo.load(f);
        chatSessionList->push_back(chatSessionInfo);
    }
}

void DataCenter::getApplyListAsync()
{
    netClient.getApplyList(loginSessionId);
}

QList<UserInfo> *DataCenter::getApplyList()
{
    return applyList;
}

void DataCenter::resetApplyList(std::shared_ptr<lch_im::GetPendingFriendEventListRsp> resp)
{
    if(applyList == nullptr) {
        applyList = new QList<UserInfo>();
    }

    // 先清空好友列表
    applyList->clear();

    auto& eventList  = resp->event();
    for(auto& e : eventList) {
        UserInfo userInfo;
        userInfo.load(e.sender());
        applyList->push_back(userInfo);
    }
}

void DataCenter::getRecentMessageListAsync(const QString &chatSessionId, bool updateUI)
{
    netClient.getRecentMessageList(loginSessionId, chatSessionId, updateUI);
}

QList<Message> *DataCenter::getRecentMessageList(const QString &chatSessionId)
{
    if (!recentMessages->contains(chatSessionId)) {
        return nullptr;
    }
    return &(*recentMessages)[chatSessionId];
}

void DataCenter::resetRecentMessageList(const QString &chatSessionId, std::shared_ptr<lch_im::GetRecentMsgRsp> resp)
{
    QList<Message>& messageList = (*recentMessages)[chatSessionId];
    messageList.clear();

    for(auto& m :resp->msgList()) {
        Message message;
        message.load(m);

        messageList.push_back(message);
    }
}

ChatSessionInfo* DataCenter::findChatSessionByUserId(const QString &userId)
{
    if(chatSessionList == nullptr) {
        return nullptr;
    }

    for(auto& info : *chatSessionList) {
        if(info.userId == userId) {
            return &info;
        }
    }

    return nullptr;
}

ChatSessionInfo *DataCenter::findChatSessionById(const QString &chatSessionId)
{
    if (chatSessionList == nullptr) {
        return nullptr;
    }
    for (auto& info : *chatSessionList) {
        if (info.chatSessionId == chatSessionId) {
            return &info;
        }
    }
    return nullptr;
}

void DataCenter::topChatSessionInfo(const ChatSessionInfo  &chatSessionInfo)
{
    if(chatSessionList == nullptr) {
        return;
    }

    auto it = chatSessionList->begin();
    for(; it != chatSessionList->end(); it++) {
        if(it->chatSessionId == chatSessionInfo.chatSessionId) {
            break;
        }
    }

    if(it == chatSessionList->end()) {
        return;
    }

    // 先备份，删除，最后插入到第一个位置上
    ChatSessionInfo backup = chatSessionInfo;
    chatSessionList->erase(it);

    chatSessionList->push_front(backup);
}

void DataCenter::setCurrentChatSessionId(const QString &chatSessionId)
{
    this->currentChatSessionId  = chatSessionId;
}

const QString &DataCenter::getCurrentChatSessionId()
{
    return this->currentChatSessionId;
}

void DataCenter::sendTextMessageAsync(const QString &chatSessionId, const QString& content)
{
    netClient.sendMessage(loginSessionId,chatSessionId,MessageType::TEXT_TYPE,content.toUtf8(),"");
}

void DataCenter::sendImageMessageAsync(const QString &chatSessionId, const QByteArray &content)
{
    netClient.sendMessage(loginSessionId, chatSessionId, MessageType::IMAGE_TYPE, content, "");
}

void DataCenter::sendFileMessageAsync(const QString& chatSessionId,const QString& filename,const QByteArray& content)
{
    netClient.sendMessage(loginSessionId,chatSessionId,MessageType::FILE_TYPE,content,filename);
}

void DataCenter::sendSpeechMessageAsync(const QString &chatSessionId, const QByteArray &speechContent)
{
    netClient.sendMessage(loginSessionId,chatSessionId,MessageType::SPEECH_TYPE,speechContent,"");
}

void DataCenter::addMessage(const Message &message)
{
    QList<Message>& messageList = (*recentMessages)[message.chatSessionId];
    messageList.push_back(message);
}

void DataCenter::changeNicknameAsync(const QString &nickname)
{
    netClient.changeNickname(loginSessionId,nickname);
}

void DataCenter::resetNickname(const QString &nickname)
{
    if(myself == nullptr) {
        return;
    }

    myself->nickname = nickname;
}

void DataCenter::changeDescriptionAsync(const QString &desc)
{
    netClient.changeDescription(loginSessionId,desc);
}

void DataCenter::resetDescription(const QString &desc)
{
    if(myself == nullptr) {
        return;
    }

    myself->description = desc;
}

void DataCenter::getVerifyCodeAsync(const QString &phone)
{
    netClient.getVerifyCode(phone);
}

void DataCenter::resetVerifyCodeId(const QString &verifyCodeId)
{
    this->currentVerifyCodeId = verifyCodeId;
}

const QString &DataCenter::getVerifyCodeId()
{
    return this->currentVerifyCodeId;
}

void DataCenter::changeAvatarAsync(const QByteArray &imageBytes)
{
    netClient.changeAvatar(loginSessionId,imageBytes);
}

void DataCenter::resetAvatar(const QByteArray &avatar)
{
    if(myself == nullptr) {
        return;
    }

    myself->avatar = createIcon(avatar);
}

void DataCenter::changePhoneAsync(const QString &phone, const QString &verifyCodeId, const QString &verifyCode)
{
    netClient.changePhone(loginSessionId,phone,verifyCodeId,verifyCode);
}

void DataCenter::resetPhone(const QString &phone)
{
    if(myself == nullptr) {
        return;
    }

    myself->phone = phone;
}

UserInfo* DataCenter::findFriendById(const QString &userId)
{
    if(friendList == nullptr) {
        return nullptr;
    }

    for(auto& f : *friendList) {
        if(f.userId == userId) {
            return &f;
        }
    }

    return nullptr;
}

void DataCenter::removeFriend(const QString &userId)
{
    if(friendList == nullptr || chatSessionList == nullptr) {
        return;
    }

    // 从好友列表中删除
    friendList->removeIf([=](const UserInfo& userInfo) {
        return userInfo.userId == userId;
    });

    // 还要删除会话
    // 如果是单聊，服务端和客户端都要删除 群聊就不管
    chatSessionList->removeIf([=](const ChatSessionInfo& chatSessionInfo){
        if(chatSessionInfo.userId == "") {
            // 群聊
            return false;
        }

        if(chatSessionInfo.userId == userId) {
            if(chatSessionInfo.chatSessionId == this->currentChatSessionId) {
                // 如果是要删除的会话，发送消息，将其删除
                emit this->clearCurrentSession();
            }
            return true;
        }
        return false;
    });
}

void DataCenter::deleteFriendAsync(const QString &userId)
{
    netClient.deleteFriend(loginSessionId,userId);
}

void DataCenter::addFriendApplyAsync(const QString &userId)
{
    netClient.addFriendApply(loginSessionId,userId);
}

void DataCenter::acceptFriendApplyAsync(const QString &userId)
{
    netClient.acceptFriendApply(loginSessionId,userId);
}

void DataCenter::rejectFriendApplyAsync(const QString &userId)
{
    netClient.rejectFriendApply(loginSessionId,userId);
}

UserInfo DataCenter::removeFromApplyList(const QString &userId)
{
    if(applyList == nullptr) {
        return UserInfo();
    }

    for(auto it = applyList->begin(); it != applyList->end(); it++) {
        if(userId == it->userId) {
            UserInfo toDelete = *it;
            applyList->erase(it);
            return toDelete;
        }
    }

    return UserInfo();
}

void DataCenter::clickDeleteFriendAsync(const QString &userId)
{
    netClient.deleteFriend(loginSessionId,userId);
}

void DataCenter::createGroupChatSessionAsync(const QList<QString>& userIdList)
{
    netClient.createGroupChatSession(loginSessionId,userIdList);
}

void DataCenter::getMemberListAsync(const QString &chatSessionId)
{
    netClient.getMemberList(loginSessionId,chatSessionId);
}

QList<UserInfo> *DataCenter::getMemberList(const QString &chatSessionId)
{
    return &(*memberList)[chatSessionId];
}

void DataCenter::resetMemberList(const QString &chatSessionId, const QList<lch_im::UserInfo> &memberList)
{
    QList<UserInfo>& currentMemberList  = (*this->memberList)[chatSessionId];
    currentMemberList.clear();

    for(const auto& u :memberList) {
        UserInfo userInfo;
        userInfo.load(u);

        currentMemberList.push_back(userInfo);
    }
}

void DataCenter::searchUserAsync(const QString &searchKey)
{
    netClient.searchUser(loginSessionId,searchKey);
}

QList<UserInfo> *DataCenter::getSearchUserResult()
{
    return searchUserInfoResult;
}

void DataCenter::resetSearchUserResult(const QList<lch_im::UserInfo> &userList)
{
    if (searchUserInfoResult == nullptr) {
        searchUserInfoResult = new QList<UserInfo>();
    }

    searchUserInfoResult->clear();

    for(const auto& u : userList) {
        UserInfo userInfo;
        userInfo.load(u);
        searchUserInfoResult->push_back(userInfo);
    }
}

void DataCenter::searchMessageAsync(const QString &searchKey)
{
    netClient.searchMessage(loginSessionId,this->currentChatSessionId,searchKey);
}

void DataCenter::searchMessageByTimeAsync(const QDateTime &begTime, const QDateTime &endTime)
{
    netClient.searchMessageByTime(loginSessionId,this->currentChatSessionId,begTime,endTime);
}

QList<Message> *DataCenter::getSearchMessageResult()
{
    return searchMessageResult;
}

void DataCenter::resetSearchMessageResult(const QList<lch_im::MessageInfo> &msgList)
{
    if(searchMessageResult == nullptr) {
        searchMessageResult = new QList<Message>();
    }

    searchMessageResult->clear();

    for(const auto& m : msgList){
        Message message;
        message.load(m);
        searchMessageResult->push_back(message);
    }
}

void DataCenter::userLoginAsync(const QString &username, const QString &password)
{
    netClient.userLogin(username,password);
}

void DataCenter::resetLoginSessionId(const QString &loginSessionId)
{
    this->loginSessionId = loginSessionId;
}

void DataCenter::userRegisterAsync(const QString &username, const QString &password)
{
    netClient.userRegister(username,password);
}

void DataCenter::phoneLoginAsync(const QString &phone, const QString &verifyCode)
{
    netClient.phoneLogin(phone,this->getVerifyCodeId(),verifyCode);
}

void DataCenter::phoneRegisterAsync(const QString &phone, const QString &verifyCode)
{
    netClient.phoneRegister(phone,this->getVerifyCodeId(),verifyCode);
}

void DataCenter::getSingleFileAsync(const QString &fileId)
{
    netClient.getSingleFile(loginSessionId,fileId);
}

void DataCenter::speechConvertTextAsync(const QString &fileId, const QByteArray &content)
{
    netClient.speechConvertText(loginSessionId,fileId,content);
}





} // end namespace
